supce's blog

CSS Secret 读书笔记之交互式的图片对比控件


交互式的图片对比控件

利用CSS可以模拟一种图片对比滑动控件,这个控件会把两张图片叠加起来,允许用户拖动分割条来控制这两张图片的显露区域。这种控件可以理解为两层结构:
下层是一张固定的图片,上层的图片则可以在水平方向上调整大小,从而能够显示下层的图片。
一般这种需求是可以利用JavaScript解决的。但是也可以利用下面这两种CSS方式。

resize方案

可以利用CSS3中的resize属性。这个属性就算没听说过,但是也肯定接触过它的行为,因为对于<textarea>元素来说,整个属性被默认设置为both,这就使得<textarea>元素在水平和垂直方向上是可以调整大小的。
对于任何一个overflow属性不是visible的元素来说,resize属性都是适用的。大部分元素resize属性的默认值是none,即禁止调整大小。该属性也接受horizontalvertical来限制元素调整大小的方向。

搞清楚resize属性,问题就很好解决了。
首先想到的是两个img元素,但是直接对一个img元素应用resize会导致图片变形失真。这时候可以在它外面包裹一个div,然后对div设置resize进行大小调整。

<div class="image-slider">
    <div>
        <img src="bad.jpg" />
    </div>
    <img src="good.jpg" />
</div>

然后给元素设置一些基本的样式,并设置好对应div元素的resize属性值:

.image-slider{
    position: relative;
    display: inline-block;
}
.image-slider>div{
    position: absolute;
    top:0;bottom:0;left:0;
    width: 40%;  /*初始宽度*/
    max-width: 100%;
    overflow: hidden;
    resize: horizontal;
}
.image-slider img{
    display: block;  /*img是一种类似text的元素,在结束的时候,
                        会在末尾加上一个空白符,所以就会多出3px 设置为block可解决*/
}

这时候的效果是这样的:

虽然在上层图片的右下角有一个调节的手柄,但是并不容易辨认。这时候可以利用一个伪元素,将其覆盖在初始的调节手柄之上。最后对伪元素进行美化:

image-slider>div::before{
    content: "";
    position: absolute;
    bottom:0;right:0;
    width: 12px;height: 12px;
    padding: 5px;
    background: linear-gradient(-45deg,white 50%,transparent 0);
    -webkit-filter: drop-shadow(0 0 2px black);
    filter: drop-shadow(0 0 2px black);
    background-clip: content-box;
    cursor: ew-resize;
}

cursor: ew-resize提供额外的自释性,可以提示用户这个区域可以进行水平方向的拖动

范围输入控件方案

利用resize属性很简单就实现了我们的需求,但是这个方案有下面几个不足:

  • 利用resize方案对于键盘来说是不可访问的
  • 只能通过拖动来调整上层图片。用户不能点击到某个点来调整宽度。
  • 用户只能在上层图片的右上角进行大小的调整,有可能被用户忽略。

为了解决上面三个问题,可以利用一点JS,将一个原生的滑动控件覆盖在图片上,用这个控件来控制上层图片的伸缩。
下面可以优化下HTML代码结构,通过JS来添加相应的元素和控件。

<div class="image-slider-2">
    <img src="bad.jpg" />
    <img src="good.jpg" />
</div>

CSS:

.image-slider-2{
    position: relative;
    display: inline-block;
}
.image-slider-2 > div{
    position: absolute;
    top:0;left:0;
    width: 50%;
    overflow: hidden;
}
.image-slider-2 img{
    display: block;
}
.image-slider-2 input{
    position: absolute;
    left:0; bottom:5px;
    width: 100%;
    margin: 0;
    /*filter: contrast(.5);
    mix-blend-mode: luminosity;*/
}

JS:

<script type="text/javascript">
    var slider = document.querySelector('.image-slider-2');
    var div = document.createElement('div');
    slider.appendChild(div);
    var img = slider.querySelector('img');
    slider.insertBefore(img,div);
    div.appendChild(img);
    //创建滑动控件
    var range = document.createElement('input');
    range.type = 'range';
    range.oninput = function(){
        div.style.width = this.value + '%';
    }
    slider.appendChild(range);
</script>

最终效果如下:

最后真的希望雾霾问题能够解决,能够给后代留一个蓝天。